import colormap from 'colormap';

// 处理结果接口
export interface ProcessedData {
  fftPoints: Array<DrawPoint>;
  maxFftPoints: Array<DrawPoint>;
  imageBitmap: ImageBitmap;
}

export type WorkerMessage =
  | { type: 'setFftData'; payload: { data: number[]; startFreq: number; stopFreq: number } }
  | { type: 'setFftRect'; payload:{ left: number;right: number; top: number; bottom: number; width: number; height: number } }
  | { type: 'setShowFreqRange'; payload: FreqRange }
  | { type: 'setShowLevelRange'; payload: { top: number; bottom: number; } }
  | { type: 'setColorMap'; payload: { scheme: string; steps?: number } }
  | { type: 'setComputeMaxFft'; payload: { computeMaxFft: boolean; } }
  | { type: 'processedData'; payload: ProcessedData };



class ViewRect {
  left: number;
  right: number;
  top: number;
  bottom: number;
  width: number;
  height: number;
  constructor(left: number, right: number, top: number, bottom: number) {
    this.left = left
    this.right = right
    this.top = top
    this.bottom = bottom
    this.width = right - left;
    this.height = bottom - top;
  }
}

// 任务队列接口
interface ProcessTask {
  id: number;
  fftData: number[];
  fftFreqRange: FreqRange; 
  timestamp: number;
};

/**
 * 频率范围
 */
interface FreqRange {
  left: number,
  right: number,
}

/**
 * 电平范围
 */
interface LevelRange {
  top: number,
  bottom: number,
}

interface DrawPoint{ 
  x: number; 
  y: number 
};

// 初始化时或数据范围变化时预计算
let freqScale: number;
let levelScale: number;
let freqOffset: number;
let levelOffset: number;

let computeMaxFft = false; // 是否计算最大值FFT
let maxFftData: number[] = []; // 最大频谱点
let maxFftFreqRange: FreqRange = {left:0,right:100};


const MAX_WATERFALL_WIDTH = 2048; // 最大瀑布图宽度
const MAX_HISTORY_LENGTH = 100; // 最大历史数据长度

const ctx: DedicatedWorkerGlobalScope = self as any; // 类型断言
let taskQueue: ProcessTask[] = []; // 任务队列
let isProcessing = false; //是否正在处理任务
let taskIdCounter = 0; //任务ID计数器

let offscreenCanvas: OffscreenCanvas = new OffscreenCanvas(MAX_WATERFALL_WIDTH, MAX_HISTORY_LENGTH); // 离屏画布
let canvasCtx: OffscreenCanvasRenderingContext2D | null = offscreenCanvas.getContext('2d', {willReadFrequently: true}); // 离屏画布上下文

let imageData: ImageData = canvasCtx?.createImageData(MAX_WATERFALL_WIDTH, MAX_HISTORY_LENGTH) as ImageData; //瀑布图绘制的图片数据
let backImageData: ImageData = canvasCtx?.createImageData(MAX_WATERFALL_WIDTH, MAX_HISTORY_LENGTH) as ImageData;; //备份瀑布图数据

let showFreqRange :FreqRange = {left:0,right:100000};
let showLevelRange :LevelRange = {top:500,bottom:-500};
let fftRect: ViewRect = new ViewRect(0,1000,0,500);

let colorScheme: { r: number; g: number; b: number }[] = [];
const DEFAULT_COLOR_STEPS = 256;

// 初始化默认颜色映射
updateColorMap('Hot', DEFAULT_COLOR_STEPS);

// 更新颜色映射
function updateColorMap(scheme: string, steps = DEFAULT_COLOR_STEPS) {
  colorScheme = colormap({
    colormap: scheme,
    nshades: steps,
    format: 'rgba',
    alpha: 1
  }).map((c: any[]) => ({
    r: c[0],
    g: c[1],
    b: c[2]
  }));
}

// 获取归一化颜色
const getColor = (level: number) => {
  if(level === showLevelRange.bottom) level = showLevelRange.bottom + 1;
  const normalized = Math.min(1, Math.max(0, (level - showLevelRange.bottom) / (showLevelRange.top - showLevelRange.bottom)));

  const index = Math.floor(normalized * (colorScheme.length - 1));
  if (index < 0 || index >= colorScheme.length) {
    console.info(`颜色索引超出范围: ${index}`);
    return { r: 0, g: 0, b: 0 };
  }
  return colorScheme[index] || { r: 0, g: 0, b: 0 };
};

// 添加任务到队列
const enqueueTask = (task: Omit<ProcessTask, 'id' | 'timestamp'>) => {
  const newTask = {
    ...task,
    id: taskIdCounter++,
    timestamp: performance.now()
  };

  // 队列容量控制（保留最新500条）
  if (taskQueue.length > 500) {
    const discarded = taskQueue.shift();
    console.warn(`队列溢出，丢弃任务#${discarded!.id}`);
  }

  taskQueue.push(newTask);

  if (!isProcessing) {
    processQueue();
  }
};

// 队列处理核心逻辑
const processQueue = async () => {
  if (taskQueue.length === 0) {
    isProcessing = false;
    return;
  }

  isProcessing = true;
  const task = taskQueue.shift()!;

  try {
    // 生成fft坐标点
    const fftPoints = await generateFftPoints(task);
    let maxFftPoints: DrawPoint[] = [];
    if(computeMaxFft){
      maxFftPoints = await generateFftMaxPoints(task);
    }
     // 生成瀑布图位图
    const imageBitmap = await generateWaterfall(task);

    ctx.postMessage({
      type: 'processedData',
      payload: {
        ...{fftPoints,maxFftPoints,imageBitmap},
        taskId: task.id,
        latency: performance.now() - task.timestamp
      }
    });
  } catch (error) {
    console.error(`处理任务#${task.id}失败:`, error);
  }

  // 继续处理下一个任务
  processQueue();
};



function updateScales() {
  // 频率计算参数
  const freqRange = showFreqRange.right - showFreqRange.left;
  freqScale = fftRect.width / freqRange;  // 避免每次计算除法
  freqOffset = -showFreqRange.left * freqScale + fftRect.left;

  // 电平计算参数
  const levelRange = showLevelRange.top - showLevelRange.bottom;
  levelScale = fftRect.height / levelRange;
  levelOffset = showLevelRange.top * levelScale + fftRect.top;
}

updateScales();

// 数据处理函数
const processFFTData = async (task: ProcessTask) => {
  const { fftData, fftFreqRange} = task;

  // 生成频谱点
  const freqStep = (fftFreqRange.right - fftFreqRange.left) / fftData.length;

  const points = fftData.map((level, index) => ({
    frequency: fftFreqRange.left + index * freqStep,
    level: Number(level.toFixed(2))
  }));

  return points;
};

const generateFftPoints = async(task: ProcessTask) => {
  const start = performance.now();

  const { fftData, fftFreqRange} = task;

  const freqStep = (fftFreqRange.right - fftFreqRange.left) / fftData.length;

  const cachedPoints = fftData.map((level,index )=> ({
    x: Math.round((freqStep * index + fftFreqRange.left) * freqScale + freqOffset),
    y: Math.round(levelOffset - level * levelScale)
  }));

  const end = performance.now();
  // console.log(`FFT计算时间计算时间: ${end - start} ms`);
  return cachedPoints;
} 

// 计算最大值FFT
const generateFftMaxPoints = async (task: ProcessTask )=> {
  const start = performance.now();
  const { fftData, fftFreqRange} = task;

  if((maxFftData.length !== fftData.length) || (maxFftFreqRange.left !== fftFreqRange.left) || (maxFftFreqRange.right !== fftFreqRange.right)){
    console.log(`更新最大值FFT`);
    maxFftData = fftData;
    console.log(maxFftFreqRange.left, maxFftFreqRange.right, fftFreqRange.left, fftFreqRange.right);
    maxFftFreqRange = fftFreqRange;
  }else{
    for(let i = 0; i < fftData.length; i++){
      if(fftData[i] > maxFftData[i]){
        maxFftData[i] = fftData[i];
      }
    }
  }

  const freqStep = (fftFreqRange.right - fftFreqRange.left) / fftData.length;

  const cachedPoints = maxFftData.map((level,index )=> ({
    x: Math.round((freqStep * index + fftFreqRange.left) * freqScale + freqOffset),
    y: Math.round(levelOffset - level * levelScale)
  }));

  const end = performance.now();
  // console.log(`最大值FFT计算时间: ${end - start} ms`);
  return cachedPoints;
}  

// 生成瀑布图位图
const generateWaterfall = async (task: ProcessTask)  => {

  const { fftData, fftFreqRange} = task;

  // const start = performance.now();
  if (!canvasCtx) throw new Error('Canvas init failed');
  if (!offscreenCanvas) {
    // 重建画布
    console.log('重建画布');
    offscreenCanvas = new OffscreenCanvas(MAX_WATERFALL_WIDTH, MAX_HISTORY_LENGTH);
    canvasCtx = offscreenCanvas.getContext('2d', {willReadFrequently: true}); // 离屏画布上下文
  
    imageData = canvasCtx?.createImageData(MAX_WATERFALL_WIDTH, MAX_HISTORY_LENGTH) as ImageData;
    backImageData = canvasCtx?.createImageData(MAX_WATERFALL_WIDTH, MAX_HISTORY_LENGTH) as ImageData;
  }

  // 动态计算需要复制的旧数据行数
  const copyHeight = MAX_HISTORY_LENGTH - 1;

  // 将旧数据复制到新数据的第二行及之后
  const startOffset = MAX_WATERFALL_WIDTH * 4; // 每行占 4*targetWidth 字节
  imageData.data.set(backImageData.data.slice(0,backImageData.data.length-startOffset), startOffset);

  let showFreqWidth = showFreqRange.right - showFreqRange.left;
  let fftFreqWidth = fftFreqRange.right - fftFreqRange.left;

  let startPx = 0;
  let endPx = MAX_WATERFALL_WIDTH;

  if(fftFreqRange.left <= showFreqRange.left){
    startPx = 0;
  }else{
    startPx = Math.floor((fftFreqRange.left - showFreqRange.left) / showFreqWidth * MAX_WATERFALL_WIDTH);
  }

  if(fftFreqRange.right >= showFreqRange.right){
    endPx = MAX_WATERFALL_WIDTH;
  }else{
    endPx = Math.floor((fftFreqRange.right - showFreqRange.left) / showFreqWidth * MAX_WATERFALL_WIDTH );
  }

  const freqStep = showFreqWidth / (endPx - startPx); // 绘制宽度的分辨率

  for (let i = startPx; i < endPx; i++) {
    const pxFreq = i * freqStep + showFreqRange.left;
    if(pxFreq < fftFreqRange.left || pxFreq > fftFreqRange.right){
      // console.log(`pxFreq: ${pxFreq} 超出范围`);
      continue;
    };
    let dataIndex = Math.floor((pxFreq - fftFreqRange.left) / fftFreqWidth * fftData.length);
    dataIndex = Math.min(fftData.length - 1, dataIndex);
    const level = fftData[dataIndex];
    const color = getColor(level);
    const idx = i * 4; // y=0行
    imageData.data.set([color.r, color.g, color.b, 255], idx);
  }
  // 备份当前数据
  backImageData.data.set(imageData.data, 0);
  // const end = performance.now();
  // console.log(`生成瀑布图时间: ${end - start} ms`);

  canvasCtx?.putImageData(imageData, 0, 0, 0, 0, MAX_WATERFALL_WIDTH, MAX_HISTORY_LENGTH);
  return offscreenCanvas.transferToImageBitmap();
}

ctx.onmessage = async (e: MessageEvent<WorkerMessage>) => {
  switch (e.data.type) {
    case 'setFftData':
      enqueueTask({
        fftData: e.data.payload.data,
        fftFreqRange: {
        left: e.data.payload.startFreq,
        right: e.data.payload.stopFreq
        }
      });
      break;

    case 'setShowLevelRange':
      if(e.data.payload != showLevelRange){
        console.log(`更新电平范围: ${showLevelRange}`);
        showLevelRange = e.data.payload;
        updateScales();
      }
      break;

    case 'setColorMap':
      updateColorMap(e.data.payload.scheme, e.data.payload.steps);
      break;

    case 'setShowFreqRange':
      if(e.data.payload != showFreqRange){
        console.log(`更新频率范围: ${showFreqRange}`);
        showFreqRange = e.data.payload;
        updateScales();
      }
      break;

      case 'setFftRect':
      if(e.data.payload != showFreqRange){
        console.log(`更新FFT矩形范围: ${fftRect}`);
        fftRect = e.data.payload;
        updateScales();
      }
      break;

      case 'setComputeMaxFft':
      computeMaxFft = e.data.payload.computeMaxFft;
      break; 
  }
};